//
//  PhoneLoginViewModel.swift
//  SwiftSign
//
//  Created by continue on 2021/5/19.
//

import UIKit
import RxSwift
import RxCocoa

class PhoneLoginViewModel: ViewModel, ViewModelType {
   
    struct Input {
        let username: Driver<String>
        let code: Driver<String>
        let sendTrigger: Driver<Void>
        let basicLoginTrigger: Driver<Void>
    }
    
    struct Output {
        let sendButtonEnabled: Driver<Bool>
        let basicLoginEnabled: Driver<Bool>
        let timer: Driver<String>
        let codeUserInteractionEnabled: Driver<Bool>
    }

    let isRunning = BehaviorRelay(value: false)
    let timer = PublishSubject<String>()
    var phone = BehaviorRelay(value: "")
    let codeUserInteractionEnabled = BehaviorRelay(value: true)
    var interval = 60
    
    func transform(input: Input) -> Output {
        
        let isUsernameValid = input.username.map { $0.count == 11 }
        let isCodeValid = input.code.map { $0.count == 6 }
        let enabled = Driver.combineLatest(isUsernameValid, isCodeValid) { $0 && $1 }
        let phoneAndCode = Driver.combineLatest(input.username, input.code) { ($0, $1 )}
            .asObservable()
    
        isRunning.asObservable().flatMapLatest { isRunning in
            isRunning ? Observable<Int>
                .interval(.seconds(1), scheduler: MainScheduler.instance) : .empty()
        }.subscribe(onNext: { [weak self] value in
            guard let self = self else { return }
            if self.interval <= 1 {
                self.isRunning.accept(false)
                self.timer.onNext("retry")
                self.codeUserInteractionEnabled.accept(true)
            } else {
                self.interval -= 1
                self.timer.onNext(self.interval.string + "s")
                self.codeUserInteractionEnabled.accept(false)
            }
           
        }).disposed(by: rx.disposeBag)
        
        input.sendTrigger.asObservable().flatMapLatest { _ in
            return self.provider
                .phoneLoginSendCode(phone: self.phone.value)
                .trackActivity(self.loading)
                .trackError(self.error)
        }.subscribe({ [weak self] (event) in
            guard let self = self else { return }
            switch event {
            case .next(let data):
                LogInfo(data)
                if data.state == 1 {
                    self.interval = 60
                    self.isRunning.accept(true)
                }
            case .error(let error):
                LogError(error.localizedDescription)
            default: break
            }
        }).disposed(by: rx.disposeBag)
        
        input.basicLoginTrigger.asObservable().withLatestFrom(phoneAndCode).flatMapLatest {  (pair) -> Observable<Event<UserInfo>>  in
            let (phone, code) = pair
            return self.provider.phoneLogin(phone: phone, code: code)
                .trackActivity(self.loading)
                .trackError(self.error)
                .materialize()
        }.subscribe(onNext: { (event) in
            switch event {
            case .next(let user):
                LogInfo(user.toJSONString() ?? "")
            case .error(let error):
                LogError(error.localizedDescription)
            default: break
            }
        }).disposed(by: rx.disposeBag)
        

        return Output(sendButtonEnabled: isUsernameValid,
                      basicLoginEnabled: enabled,
                      timer: timer.asDriverOnErrorJustComplete(),
                      codeUserInteractionEnabled: codeUserInteractionEnabled.asDriver())
    }
}
